﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace System
{
    /// <summary>
    /// 表示<see cref="System.Exception"/>的扩展方法
    /// </summary>
    /// <creator>marc</creator>
    public static class ExceptionExtensions
    {
        /// <summary>
        /// 表示聚合后的消息。多条异常消息将聚合为一条消息
        /// </summary>
        /// <param name="exp"><inheritdoc cref="GetInnerMessage(System.Exception, string)" path="/param[@name='exp']"/></param>
        /// <returns></returns>
        public static string InnerAggregateMessage(this Exception exp)
        {
            return InnerMessages(exp, "\r\n").JoinAsString("\r\n\r\n");
        }

        /// <summary>
        /// 表示异常的消息列表，多个异常对应多条消息
        /// </summary>
        /// <param name="exp"><inheritdoc cref="GetInnerMessage(System.Exception, string)" path="/param[@name='exp']"/></param>
        /// <param name="separator"><inheritdoc cref="GetInnerMessage(System.Exception, string)" path="/param[@name='separator']"/></param>
        /// <returns></returns>
        public static IReadOnlyList<string> InnerMessages(this Exception exp, string separator)
        {
            List<string> message = new List<string>();
            if (exp is System.AggregateException aggregateException)
            {
                aggregateException.InnerExceptions?.ForEach((innerException) =>
                {
                    message.Add(GetInnerMessage(exp, separator));
                });
            }
            else
            {
                message.Add(GetInnerMessage(exp, separator));
            }

            return message.AsReadOnly();
        }

        /// <summary>
        /// 获取异常的实际消息
        /// </summary>
        /// <param name="exp">代表一个异常<see cref="System.Exception"/></param>
        /// <param name="separator">表示连接字符串时的分隔符</param>
        /// <returns>返回内部异常信息描述</returns>
        private static string GetInnerMessage(Exception exp, string separator)
        {
            if (exp.InnerException == null)
            {
                return string.Join(separator, exp.GetType(), exp.Message);
            }

            return GetInnerMessage(exp.InnerException, separator);
        }
    }
}
